/*
 * file:  program.h (contains declarations of Program, StmtList, Stmt, Expr)
 * Author: Jeremy Johnson 
 * Date: 2/05/07
 *
 * Description:
 */
#include <iostream>
#include <string>
#include <map>
#include <list>

using namespace std;

// Enumerators for RAL instructions
enum Operators { LD , ST , ADD , SUB , JMN , JMZ, HLT, LBL, JMP, MUL , LDI , LDA , STI ,STA , UNK, JMI, CAL, RTN };

enum Types { CONST , LABEL , TEMP , LOCAL , UNDEFINED, OFFSET };

class RAMInstruction
{
public: 
	RAMInstruction(Operators oper = UNK, string operand = "", int lineNumber = 0, Types type = UNDEFINED);
	int getLineNumber();
	int setLineNumber(int LnNum);
	void setConstantValue(string constantvalue);
	string getConstantValue();
	Operators getOper();
	Operators getLinkedOper();
	int getLinkedOperand();
	Types getType();
	void setLinked(Operators oper, int operand); 
	string getOperString();
	string getLinkedOperString();
	string getOperand();
private: 
	int lineNumber_;
	Operators oper_;
	string operand_; 
	Types type_; 
	Operators linkedoper_;
	int linkedoperand_;
	string constantvalue_;
};

class RAMCounter
{
public: 
	RAMCounter();
	int getActRecordSize(string name);
	string getNextConstant(int value);
	string getNextTemporary();
	string getNextLabel();
	string getNextParam(int value);
	string CurrentFunc_;
	void link();
	void memory();
	void dump();
	void addInstruction(Operators oper, string operand, Types type); 
	void addLabel(string lbl); 
	void optimize();
	void createActRecord(string);
	void createActRecIndex(string,string);
	void resetActRecIndex();
	void clearTables();
private:
	list<RAMInstruction> instructions_;
	int constant_;
	int temporary_;
	int label_;
	int lineCounter_;
	int param_;
	int actRecIndex_;
	int ftemporary_;
	int flocal_;
	int fparam_;
	map<string,int> constantTable_;
	map<string,int> localTable_;
	map<string,int> tempTable_;
	map<string,int> labelTable_;
	map<string,int> offsetValueTable_;
	map<string,int> offsetTable_;
	map<string,int> paramTable_;
	map<string,int> ConstantValueTable_;
	map<string,int> ParamValueTable_;
	map<string,int> FuncTable_;
	map<string,int> FtempTable_;
	map<string,int> FlocalTable_;
	map<string,int> FparamTable_;
	map<string,int> actRecSizeTable_;
	map<string,map<string,int> > actRecord_;
};
// forward declarations 
// StmtList used by IfStmt and WhileStmt which are Stmt
// Proc which contains StmtList used in Expr, Stmt, StmtList 
class StmtList;
class Proc;

class Expr
{
public:
	Expr() {};
	virtual ~Expr() {};  
	virtual int eval(map<string,int> NT, map<string,Proc*> FT) const = 0;  
	virtual string translate(map<string,int> T, RAMCounter &rc) const = 0;

private:
};

class Number : public Expr
{
public:
	Number(int value = 0);
	virtual int eval(map<string,int> NT, map<string,Proc*> FT) const;
	virtual string translate(map<string,int> T, RAMCounter &rc) const;
private:
	int value_;
};


class Ident : public Expr
{
public:
	Ident(string name = "");
	virtual int eval(map<string,int> NT, map<string,Proc*> FT) const;
	string translate(map<string,int> T, RAMCounter &rc) const;
private:
	string name_;
};

class Times : public Expr
{
public:
	Times(Expr * op1 = NULL, Expr * op2 = NULL);
	virtual ~Times() {delete op1_; delete op2_;};
	virtual int eval(map<string,int> NT, map<string,Proc*> FT) const;
	string translate(map<string,int> T, RAMCounter &rc) const;
private:
	Expr* op1_;
	Expr* op2_;
};

class Plus : public Expr
{
public:
	Plus(Expr* op1 = NULL, Expr* op2 = NULL);
	virtual ~Plus() {delete op1_; delete op2_;};
	virtual int eval(map<string,int> NT, map<string,Proc*> FT) const;
	string translate(map<string,int> T, RAMCounter &rc) const;
private:
	Expr* op1_;
	Expr* op2_;
};

class Minus : public Expr
{
public:
	Minus(Expr* op1 = NULL, Expr* op2 = NULL);
	virtual ~Minus() {delete op1_; delete op2_;};
	virtual int eval(map<string,int> NT, map<string,Proc*> FT) const;
	string translate(map<string,int> T, RAMCounter &rc) const;
private:
	Expr* op1_;
	Expr* op2_;
};

class FunCall : public Expr
{
public:
	FunCall(string name, list<Expr*> *AL);
	virtual ~FunCall();
	virtual int eval(map<string,int> NT, map<string,Proc*> FT) const;
	string translate(map<string,int> T, RAMCounter &rc) const;
private:
	string name_;
	list<Expr*> *AL_;
};


class Stmt 
{
public:
	Stmt() {};
	virtual ~Stmt() {};  
	virtual void eval(map<string,int> &NT, map<string,Proc*> &FT) const = 0;  
	virtual void translate(map<string,int> &T, RAMCounter &rc) const = 0;

private:
};


class AssignStmt: public Stmt
{
public:
	AssignStmt(string name="", Expr *E=NULL);
	~AssignStmt() {delete E_;}; 
	void eval(map<string,int> &NT, map<string,Proc*> &FT) const;
	void translate(map<string,int> &T, RAMCounter &rc) const;
private:
	string name_;
	Expr* E_;
};

class DefineStmt : public Stmt
{ 
public:
	DefineStmt(string name="", Proc *P=NULL);
	virtual ~DefineStmt();  
	virtual void eval(map<string,int> &NT, map<string,Proc*> &FT) const;  
	virtual void translate(map<string,int> &T, RAMCounter &rc) const;  
private:
	string name_;
	Proc* P_;
	RAMCounter Temprc_;
};


class IfStmt: public Stmt
{
public:
	IfStmt(Expr *E,StmtList *S1, StmtList *S2);
	~IfStmt();
	void eval(map<string,int> &NT, map<string,Proc*> &FT) const;
	void translate(map<string,int> &T, RAMCounter &rc) const;
private:
	Expr* E_;
	StmtList *S1_;
	StmtList *S2_;
};

class WhileStmt: public Stmt
{
public:
	WhileStmt(Expr *E,StmtList *S);
        ~WhileStmt();
	void eval(map<string,int> &NT, map<string,Proc*> &FT) const;
	void translate(map<string,int> &T, RAMCounter &rc) const;
private:
	Expr* E_;
	StmtList *S_;
};


class StmtList 
{
public:
	StmtList() {};
	void eval(map<string,int> &NT, map<string,Proc*> &FT);  
	void insert(Stmt *T);  
	void translate(map<string,int> &T, RAMCounter &rc);

private:
	list<Stmt*> SL_;
};

class Proc
{
public:
	Proc(list<string> *PL, StmtList *SL);
	~Proc() {delete SL_; };  
	int apply(map<string,int> &NT, map<string,Proc*> &FT, list<Expr*> *EL);
	void translate(map<string,int> &t, RAMCounter &rc);
private:
	StmtList *SL_;
	list<string> *PL_;
	int NumParam_;
	RAMCounter FuncRamCounter_;
};

class Program 
{
public:
	Program(StmtList *SL, bool optimizer_);
	~Program() {delete SL_; };  
	void dump();
	void memory();
	void eval();  
	void translate();
	void compile();

private:
	StmtList *SL_;
	map<string,int> SymbolTable_;
	map<string,int> NameTable_;
	map<string,Proc*> FunctionTable_;
	RAMCounter RAMCounter_;
	bool optimizer;
};
